[rl] RendererConfig silently drops the removed preserve_* renderer knobs - #4365
[rl] RendererConfig silently drops the removed preserve_* renderer knobs#4365andylizf wants to merge 3 commits into
Conversation
…tention through auto renderers replaced preserve_all_thinking and preserve_thinking_between_tool_calls with a single thinking_retention enum (PrimeIntellect-ai/renderers#88). Neither name is a field on a renderer config any more, so RendererConfig.build, which forwards by matching field names, drops both without a word -- and drops them before the library's own validator, which raises and names the replacement, can see them. Forward thinking_retention as its own field, and raise when a removed knob is set to True and the resolved config cannot take it. On the auto path (name=None or "auto") the library's AutoRendererConfig carries thinking_retention into the resolved config and nothing else, so forward that one knob there and raise for the rest instead of dropping them. An explicit False is left alone: it meant "defer to the chat template", which is what dropping it does.
|
Hi @andylizf! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
The following ciflow label(s) have been added but CI has not been triggered yet because the workflows are awaiting approval:
Once a maintainer approves the workflows (scroll to the bottom of the PR page), the corresponding CI jobs will be triggered automatically. Please ping one of the reviewers if you do not have access to approve and run workflows. |
|
hey @andylizf , thanks for the PR! I am on PTO until Monday. I will try to review over the weekend. If not, i will do it on Tuesday |
| enable_thinking: Let the model emit reasoning, when supported. | ||
| preserve_all_thinking: Keep historical reasoning in future prompts. | ||
| preserve_thinking_between_tool_calls: Keep reasoning during tool loops. | ||
| preserve_all_thinking: Removed upstream; see `thinking_retention`. |
There was a problem hiding this comment.
we dont really do backward compatibility. If this is a dead knob, lets remove it
| renderer_name = _RENDERER_BY_MODEL.get(self.name, self.name) | ||
| renderer_config = config_from_name(renderer_name) if renderer_name else None | ||
|
|
||
| # `renderers` replaced these two bools with the single `thinking_retention` |
There was a problem hiding this comment.
same here, no need to keep comments about historical motivation
|
@claude please review. What is a robust and elegant/simple way of forwarding configs without silently allowing errors like this? please think of 3 ideas with code snippets. Dont be verbose. |
|
Claude finished @felipemello1's task in 46s —— View job Forwarding configs without silent dropsThe root cause is the Idea 1 — Delegate to the library's own guard (simplest, my pick). args = {
f.name: getattr(self, f.name)
for f in fields(self)
if f.name != "name" and getattr(self, f.name) is not None
}
# config_type has extra="forbid" + a validator naming thinking_retention,
# so a removed/typo'd knob raises here instead of vanishing.
return create_renderer(tokenizer, config_type(**args))Idea 2 — Don't mirror the schema at all. name: str | None = None
options: dict[str, Any] = field(default_factory=dict) # forwarded verbatim
...
config_type(**self.options) # unknown keys -> pydantic raisesTrade-off: loses per-field typing/discoverability in TorchTitan's config. Good when the wrapped schema churns often. Idea 3 — Explicit diff, if you want to keep the typed mirror. provided = {f.name for f in fields(self)
if f.name != "name" and getattr(self, f.name) is not None}
unknown = provided - config_type.model_fields.keys()
if unknown:
raise ValueError(f"{sorted(unknown)} not accepted by {config_type.__name__}")Recommendation: Idea 1. It deletes code, removes the mirror-vs-library drift entirely, and reuses the guard Want me to push this simplification to the branch? |
…d renderer knobs strictly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig forwards every set knob to the renderer's typed pydantic config without filtering by field name, so a knob the renderer lacks raises (extra="forbid") instead of being silently dropped (pytorch#4365). The removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are deleted; thinking_retention is added. Renderer names are the library's names (_RENDERER_BY_MODEL removed). Two configs that silently lost enable_thinking today (gpt-oss alphabet sort, muse_glimmer search_r1) drop the knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d renderer knobs strictly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig forwards every set knob to the renderer's typed pydantic config without filtering by field name, so a knob the renderer lacks raises (extra="forbid") instead of being silently dropped (pytorch#4365). The removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are deleted; thinking_retention is added. Renderer names are the library's names (_RENDERER_BY_MODEL removed). Two configs that silently lost enable_thinking today (gpt-oss alphabet sort, muse_glimmer search_r1) drop the knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d renderer knobs strictly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig forwards every set knob to the renderer's typed pydantic config without filtering by field name, so a knob the renderer lacks raises (extra="forbid") instead of being silently dropped (pytorch#4365). The removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are deleted; thinking_retention is added. Renderer names are the library's names (_RENDERER_BY_MODEL removed). Two configs that silently lost enable_thinking today (gpt-oss alphabet sort, muse_glimmer search_r1) drop the knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d renderer knobs strictly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig forwards every set knob to the renderer's typed pydantic config without filtering by field name, so a knob the renderer lacks raises (extra="forbid") instead of being silently dropped (pytorch#4365). The removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are deleted; thinking_retention is added. Renderer names are the library's names (_RENDERER_BY_MODEL removed). Two configs that silently lost enable_thinking today (gpt-oss alphabet sort, muse_glimmer search_r1) drop the knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d renderer knobs strictly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig forwards every set knob to the renderer's typed pydantic config without filtering by field name, so a knob the renderer lacks raises (extra="forbid") instead of being silently dropped (pytorch#4365). The removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are deleted; thinking_retention is added. Renderer names are the library's names (_RENDERER_BY_MODEL removed). Two configs that silently lost enable_thinking today (gpt-oss alphabet sort, muse_glimmer search_r1) drop the knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d renderer knobs strictly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig forwards every set knob to the renderer's typed pydantic config without filtering by field name, so a knob the renderer lacks raises (extra="forbid") instead of being silently dropped (pytorch#4365). The removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are deleted; thinking_retention is added. Renderer names are the library's names (_RENDERER_BY_MODEL removed). Two configs that silently lost enable_thinking today (gpt-oss alphabet sort, muse_glimmer search_r1) drop the knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…enderer options through renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer, so RendererConfig.build now takes TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer. The controller reads pad_id off its own tokenizer instead of renderer._tokenizer. RendererConfig is now `name` + `options`: the options dict is passed unchanged to the renderer's typed pydantic config, which rejects options that renderer does not have (extra="forbid") instead of TorchTitan silently dropping them (pytorch#4365). TorchTitan no longer mirrors renderer fields; the removed preserve_* knobs and the DefaultRenderer-only tool_parser/reasoning_parser are gone, and renderer names are the library's names (_RENDERER_BY_MODEL removed). Recipes move to options={...}; the gpt-oss alphabet-sort recipe, whose enable_thinking=False was being dropped, now sets reasoning_effort="low". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam; Muse Glimmer's in-tree renderer registers itself when its module is imported, which unpickling its config in a rollout worker does. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam; Muse Glimmer's in-tree renderer registers itself when its module is imported, which unpickling its config in a rollout worker does. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has an InTreeRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former never matches a local checkpoint path, the latter needs Hugging Face's apply_chat_template, which TorchTitan's template rendering does not match. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has an InTreeRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former never matches a local checkpoint path, the latter needs Hugging Face's apply_chat_template, which TorchTitan's template rendering does not match. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has an InTreeRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has a TorchTitanRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has a TorchTitanRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has a TorchTitanRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has a TorchTitanRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has a TorchTitanRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he renderer's typed config directly renderers 0.1.11 makes transformers optional and accepts a bring-your-own tokenizer. RL now renders with TorchTitan's HuggingFaceTokenizer (wrapped in RendererTokenizer to satisfy renderers.OffsetTokenizer) instead of loading transformers.AutoTokenizer, and the controller reads pad_id off its own tokenizer instead of renderer._tokenizer. TorchTitan's RendererConfig wrapper is removed. Controller.Config.renderer is the library's own typed pydantic config (Qwen3RendererConfig(enable_thinking=False), GptOssRendererConfig(reasoning_effort="low"), ...), so a wrong option fails when the recipe is constructed instead of being silently dropped (pytorch#4365), and TorchTitan mirrors no renderer fields. build_renderer(tokenizer, config) is the one TorchTitan-side seam. A renderer that ships in TorchTitan (Muse Glimmer) has a TorchTitanRendererConfig that names its renderer class, and build_renderer constructs it directly, so nothing is written into renderers' registry. AutoRendererConfig and DefaultRendererConfig are rejected with the reason: the former depends on an exact model-ID match that local asset paths do not reliably preserve; the latter needs Hugging Face-compatible apply_chat_template semantics, which TorchTitan's template rendering does not provide. Renderer options are set in the recipe (tyro.conf.Suppress, like model_spec); the 8 redundant --renderer.enable-thinking CLI flags in the integration tests are removed. Configurable.to_dict learns pydantic model_dump so the wandb config stays JSON. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
RendererConfig.buildforwards knobs to therenderersconfig by matching fieldnames, and drops anything that does not match:
renderersreplacedpreserve_all_thinkingandpreserve_thinking_between_tool_callswith a single
thinking_retentionenum in PrimeIntellect-ai/renderers#88 (2026-06-26).Neither name is a field on a renderer config any more, so both are dropped. Both are
still declared on
RendererConfigand documented in its docstring, andcomponents/training_sample_builder.pyrecommends settingpreserve_all_thinking=Trueto keep thinking from being stripped out of history.
experiments/rl/requirements.txttracks
renderersatmain, so the knobs have been inert since that commit.The drop is silent, and it defeats a guard the library added for this case:
rendererskeeps a validator that raises
"[...] were replaced by thinking_retention"when an oldname reaches it, and the typed configs use
extra="forbid". The name filter removes thefield before either can see it. Startup logs the result without flagging it:
Where we hit it: a recipe setting
preserve_all_thinking=Trueran under the renderer'simplied
tool_cyclepolicy instead. For an agent loop that returns tool output as plainuser messages, every turn reads as a new user query, so
bridge_to_next_turnrefuses tocontinue and the trajectory is re-rendered from scratch — 40694 of 40697 turns in one
run, against a code comment that expects zero. On a hybrid model without prefix caching
that is a full recompute per turn.
This PR:
thinking_retentiontoRendererConfigso callers have a working path, typedas the library's
Literal["tool_cycle", "all"].Trueand the resolved config cannot take it,naming the replacement. An explicit
Falseis left alone: it meant "defer to thechat template", which is what dropping it already does.
thinking_retentionon the auto path by constructingAutoRendererConfig,which the library provides precisely to carry it through tokenizer-based resolution.
Other knobs set there still reach nothing, so they raise rather than being ignored,
and
create_renderer(tokenizer, None)is kept unchanged when nothing is set.Verified against the installed
renderers:thinking_retentionthrough auto resolves tothe same config object as naming the renderer explicitly, across all 53 models in
MODEL_RENDERER_MAP;create_renderer(tokenizer, None)andcreate_renderer(tokenizer, AutoRendererConfig())are equivalent; a matrix over names(
None,"auto","qwen3", unknown) x both legacy fields (None/False/True) xretention set/unset behaves as described; and existing callers that set only
nameandenable_thinking, or passtool_parseralongside a model-specific renderer, areunaffected.
One gap left alone:
config_from_name()still runs before the removed-knob check, so anunknown renderer name reports that first and masks the legacy message. I can reorder it
if you would rather the legacy message win.